/**************************************************************
 *   File:	Window.cpp
 * Author:	Andrew Thorpe
 *  Brief:	A class to create a Win32 pWindow and OpenGL
 *			rendering context
 **************************************************************/
#include "StdAfx.h"
#include "Window.h"
#include "Renderer.h"

using namespace Fossil;
Window* Window::Create(const char *title, int x, int y, int width, int height, int bits, bool fullscreen)
{
	Window* pWindow			= new Window();
	pWindow->m_Title		= title;
	pWindow->m_X			= x;
	pWindow->m_Y			= y;
	pWindow->m_Width		= width;
	pWindow->m_Height		= height;
	pWindow->m_Bits			= bits;
	pWindow->m_Fullscreen	= fullscreen;
	pWindow->m_ClassName	= title;

	unsigned int		PixelFormat;
	WNDCLASS			wc;
	DWORD				dwExStyle;
	DWORD				dwStyle;
	RECT				WindowRect;	
	WindowRect.left		= (long)x;
	WindowRect.right	= (long)width;
	WindowRect.top		= (long)y;
	WindowRect.bottom	= (long)height;


	pWindow->m_hInstance	= GetModuleHandle(NULL);
	wc.style				= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc			= (WNDPROC) Window::WndProc;
	wc.cbClsExtra			= 0;
	wc.cbWndExtra			= 0;
	wc.hInstance			= pWindow->m_hInstance;
	wc.hIcon				= LoadIcon(NULL, IDI_WINLOGO);
	wc.hCursor				= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground		= NULL;
	wc.lpszMenuName			= NULL;
	wc.lpszClassName		= pWindow->m_ClassName;

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}
	
	if (fullscreen)
	{
		DEVMODE dmScreenSettings;
		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
		dmScreenSettings.dmSize			= sizeof(dmScreenSettings);
		dmScreenSettings.dmPelsWidth	= width;
		dmScreenSettings.dmPelsHeight	= height;
		dmScreenSettings.dmBitsPerPel	= bits;
		dmScreenSettings.dmFields		= DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			if (MessageBox(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", title, MB_YESNO|MB_ICONEXCLAMATION) == IDYES)
			{
				pWindow->m_Fullscreen = false;
			}
			else
			{
				MessageBox(NULL, "Program Will Now Close.", "ERROR", MB_OK|MB_ICONSTOP);
				return NULL;
			}
		}
	}

	if (fullscreen)
	{
		dwExStyle	= WS_EX_APPWINDOW;
		dwStyle		= WS_POPUP;
		ShowCursor(FALSE);
	}
	else
	{
		dwExStyle	= WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
		dwStyle		= WS_OVERLAPPEDWINDOW;
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

	
	pWindow->m_hWnd = CreateWindowEx(	dwExStyle,
										pWindow->m_ClassName,
										title,
										dwStyle |
										WS_CLIPSIBLINGS |
										WS_CLIPCHILDREN,
										WindowRect.left, 
										WindowRect.top,
										WindowRect.right - WindowRect.left,
										WindowRect.bottom - WindowRect.top,
										NULL,
										NULL,
										pWindow->m_hInstance,
										NULL);
	if (!(pWindow->m_hWnd))
	{
		pWindow->Destroy();
		MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	static	PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW |
		PFD_SUPPORT_OPENGL |
		PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		(BYTE)bits,
		0, 0, 0, 0, 0, 0,
		0,
		0,
		0,
		0, 0, 0, 0,
		16, 
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0, 0, 0
	};

	pWindow->m_hDc = GetDC(pWindow->m_hWnd);

	if (!pWindow->m_hDc)
	{
		pWindow->Destroy();
		MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	PixelFormat = ChoosePixelFormat(pWindow->m_hDc, &pfd);
	if (!(PixelFormat))
	{
		pWindow->Destroy();
		MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	if(!SetPixelFormat(pWindow->m_hDc, PixelFormat, &pfd))
	{
		pWindow->Destroy();
		MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	pWindow->m_hRc = wglCreateContext(pWindow->m_hDc);
	if (!(pWindow->m_hRc))
	{
		pWindow->Destroy();
		MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	if(!wglMakeCurrent(pWindow->m_hDc, pWindow->m_hRc))
	{
		pWindow->Destroy();
		MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
		return NULL;
	}

	ShowWindow(pWindow->m_hWnd,SW_SHOW);
	SetForegroundWindow(pWindow->m_hWnd);
	SetFocus(pWindow->m_hWnd);

	return pWindow;
}

void Window::Destroy()
{
	if (m_Fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
		ShowCursor(TRUE);
	}

	if (m_hRc)
	{
		if (!wglMakeCurrent(NULL, NULL))
		{
			MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(m_hRc))
		{
			MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		}
		m_hRc = NULL;
	}

	if (m_hDc && !ReleaseDC(m_hWnd, m_hDc))
	{
		MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		m_hDc = NULL;
	}

	if (m_hWnd && !DestroyWindow(m_hWnd))
	{
		MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		m_hWnd=NULL;
	}

	if (!UnregisterClass(m_ClassName, m_hInstance))
	{
		MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		m_hInstance = NULL;
	}
}

LRESULT CALLBACK Window::WndProc(	HWND	hWnd,
									UINT	uMsg,
									WPARAM	wParam,
									LPARAM	lParam)
{
	switch (uMsg)
	{
		case WM_ACTIVATE:
		{
			return 0;
		}

		case WM_SYSCOMMAND:
		{
			switch (wParam)
			{
				case SC_SCREENSAVE:
				case SC_MONITORPOWER:
				return 0;
			}
			break;
		}

		case WM_CLOSE:
		{
			PostQuitMessage(0);
			return 0;
		}

		case WM_KEYDOWN:
		{
			return 0;
		}

		case WM_KEYUP:
		{
			return 0;
		}

		case WM_CHAR:
		{
		}
		break; 

		case WM_SIZE:
		{
			Renderer::Instance()->Resize(LOWORD(lParam), HIWORD(lParam));
		}

		case WM_MOUSEMOVE:
		{
		}
		break;

		case WM_LBUTTONDOWN:
		{
		}
		break;

		case WM_RBUTTONDOWN:
		{
		}
		break;

		case WM_LBUTTONUP:
		{
		}
		break;

		case WM_RBUTTONUP:
		{
		}
		break;
	}
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

